This file is used to identify specific markers for ORS and IFE basal.

library(dplyr)
library(patchwork)
library(ggplot2)
library(ComplexHeatmap)

.libPaths()
## [1] "/usr/local/lib/R/library"

Preparation

In this section, we set the global settings of the analysis. We will store data there :

out_dir = "."

We load the dataset :

sobj = readRDS(paste0(out_dir, "/hs_hd_sobj.rds"))
sobj
## An object of class Seurat 
## 20003 features across 12111 samples within 1 assay 
## Active assay: RNA (20003 features, 2000 variable features)
##  6 dimensional reductions calculated: RNA_pca, RNA_pca_38_tsne, RNA_pca_38_umap, harmony, harmony_38_umap, harmony_38_tsne

We load the sample information :

sample_info = readRDS(paste0(out_dir, "/../1_metadata/hs_hd_sample_info.rds"))
project_names_oi = sample_info$project_name

graphics::pie(rep(1, nrow(sample_info)),
              col = sample_info$color,
              labels = sample_info$project_name)

Here are custom colors for each cell type :

color_markers = readRDS(paste0(out_dir, "/../1_metadata/hs_hd_color_markers.rds"))

data.frame(cell_type = names(color_markers),
           color = unlist(color_markers)) %>%
  ggplot2::ggplot(., aes(x = cell_type, y = 0, fill = cell_type)) +
  ggplot2::geom_point(pch = 21, size = 5) +
  ggplot2::scale_fill_manual(values = unlist(color_markers), breaks = names(color_markers)) +
  ggplot2::theme_classic() +
  ggplot2::theme(legend.position = "none",
                 axis.line = element_blank(),
                 axis.title = element_blank(),
                 axis.ticks = element_blank(),
                 axis.text.y = element_blank(),
                 axis.text.x = element_text(angle = 30, hjust = 1))

This is the projection of interest :

name2D = "harmony_38_tsne"

We design a custom function to make a histogram and a wordcloud to visualize differentially expressed genes :

hist_wc_fun = function(mark, col) {
  cut_colors = c("firebrick4", "firebrick2", "indianred1", "darksalmon",
                 "lightpink", "gray50", "khaki3", "darkolivegreen1",
                 "olivedrab1", "chartreuse2", "chartreuse4")
  cut_colors_cont = c(rev(RColorBrewer::brewer.pal(name = "Reds", n = 9)[c(5:9)]),
                      RColorBrewer::brewer.pal(name = "Greens", n = 9)[c(5:9)])
  
  if (col == "pct.1") {
    mark$pct = mark$pct.1
    mark$pct_cut = mark$pct.1_cut
  } else if (col == "pct.2") {
    mark$pct = mark$pct.2
    mark$pct_cut = mark$pct.2_cut
    cut_colors = rev(cut_colors)
    cut_colors_cont = rev(cut_colors_cont)
  } else {
    stop("col must be either pct.1 or pct.2")
  }
  
  p_hist = ggplot2::ggplot(mark, mapping = aes(x = avg_logFC, fill = pct_cut)) +
    ggplot2::geom_histogram(binwidth = 0.05) +
    ggplot2::scale_fill_manual(breaks = levels(mark$pct_cut),
                               values = cut_colors,
                               name = paste0(col, "_cut")) +
    ggplot2::theme_classic()
  
  p_wc = ggplot2::ggplot(mark, aes(label = gene_name, size = avg_logFC, color = pct)) +
    ggwordcloud::geom_text_wordcloud_area(show.legend = TRUE, seed = 1) +
    ggplot2::scale_color_gradientn(colors = cut_colors_cont,
                                   name = col) +
    ggplot2::scale_size_area(max_size = 5) +
    ggplot2::theme_minimal() +
    ggplot2::guides(size = "none")
  
  p = patchwork::wrap_plots(p_hist, p_wc, nrow = 1)
  
  return(p)
}

Visualization

Gene expression

We visualize gene expression for some markers :

features = c("percent.mt", "percent.rb", "nFeature_RNA")

plot_list = lapply(features, FUN = function(one_gene) {
  Seurat::FeaturePlot(sobj, features = one_gene,
                      reduction = name2D) +
    ggplot2::theme(aspect.ratio = 1) +
    ggplot2::scale_color_gradientn(colors = aquarius::color_gene) +
    Seurat::NoAxes()
})

patchwork::wrap_plots(plot_list, ncol = 3)

Cluster type Clusters and cell type

We visualize clusters and cell type :

cluster_plot = Seurat::DimPlot(sobj, group.by = "seurat_clusters",
                               reduction = name2D, label = TRUE) +
  ggplot2::labs(title = "Cluster ID") +
  Seurat::NoAxes() +
  ggplot2::theme(aspect.ratio = 1,
                 plot.title = element_text(hjust = 0.5))

cell_type_plot = Seurat::DimPlot(sobj, group.by = "cell_type",
                                 reduction = name2D, label = FALSE) +
  ggplot2::scale_color_manual(values = color_markers,
                              breaks = names(color_markers)) +
  ggplot2::labs(title = "Cell type") +
  Seurat::NoAxes() +
  ggplot2::theme(aspect.ratio = 1,
                 plot.title = element_text(hjust = 0.5))

cell_type_plot | cluster_plot

We summarize major cell type by cluster :

cell_type_clusters = sobj@meta.data[, c("cell_type", "seurat_clusters")] %>%
  table() %>%
  prop.table(., margin = 2) %>%
  apply(., 2, which.max)
cell_type_clusters = setNames(levels(sobj$cell_type)[cell_type_clusters],
                              nm = names(cell_type_clusters))

We define cluster type :

sobj$cluster_type = cell_type_clusters[sobj$seurat_clusters] %>%
  as.factor()
table(sobj$cluster_type, sobj$cell_type)
##                       
##                        CD4 T cells CD8 T cells Langerhans cells macrophages
##   B cells                        0           0                0           0
##   CD4 T cells                  774          52                2           1
##   CD8 T cells                   86         545                1           0
##   HF-SCs                         0           0                0           0
##   IFE basal                      2           0                0           0
##   IFE granular spinous           0           0                0           0
##   IRS                            0           0                0           0
##   Langerhans cells              15           0              253          51
##   ORS                            0           0                0           0
##   cortex                         0           0                0           0
##   cuticle                        1           0                0           0
##   macrophages                    9           0               26         423
##   medulla                        0           0                0           0
##   proliferative                  0           0                3           0
##   sebocytes                      0           0                0           0
##                       
##                        B cells cuticle cortex medulla  IRS proliferative  ORS
##   B cells                   37       0      0       1    0             0    0
##   CD4 T cells                3       2      0       3    3             2    1
##   CD8 T cells                4       0      0       0    0             0    0
##   HF-SCs                     2       4      0       2    2             9   41
##   IFE basal                  3       5      2      15    6            23   21
##   IFE granular spinous       1       1      0       0    0             2   25
##   IRS                        0       0      0       0  155             4    0
##   Langerhans cells           1       1      1       0    2            23    2
##   ORS                        1       4      0       5    1            23 1502
##   cortex                     0     105    199       4    0             0    0
##   cuticle                    0     804     29      21    0             1    0
##   macrophages                1       0      0       0    1             0    0
##   medulla                    1      26      1     335    0            17    0
##   proliferative             12     318      8      42  126          1384   44
##   sebocytes                  0       0      1       1    0             1    0
##                       
##                        IFE basal IFE granular spinous HF-SCs sebocytes
##   B cells                      0                    0      0         0
##   CD4 T cells                  0                    0      0         0
##   CD8 T cells                  0                    0      0         0
##   HF-SCs                     104                    3   1286         1
##   IFE basal                 1779                   57     44        16
##   IFE granular spinous        66                  498      7        13
##   IRS                          0                    0      0         0
##   Langerhans cells             0                    0      1         2
##   ORS                         11                  113     23         7
##   cortex                       0                    0      0         0
##   cuticle                      0                    0      0         2
##   macrophages                  0                    0      0         0
##   medulla                      0                    0      1         0
##   proliferative               75                   71     24        18
##   sebocytes                   63                    1      0       154

We compare cluster annotation and cell type annotation :

cell_type_plot

p2 = Seurat::DimPlot(sobj, group.by = "cluster_type",
                     reduction = name2D, cols = color_markers) +
  ggplot2::labs(title = "Cluster type") +
  Seurat::NoAxes() +
  ggplot2::theme(aspect.ratio = 1,
                 plot.title = element_text(hjust = 0.5))

patchwork::wrap_plots(cell_type_plot, p2, guides = "collect")

There is mis-annotation, so we keep the single-cell level cell type annotation.

Differential expression

In this section, we perform DE between interfollicular epidermis (IFE) basal or outer root sheath (ORS), and all remaining cells. We save the results in a list :

list_results = list()

We change cell identities to cell type :

Seurat::Idents(sobj) = sobj$cell_type

table(Seurat::Idents(sobj))
## 
##          CD4 T cells          CD8 T cells     Langerhans cells 
##                  887                  597                  285 
##          macrophages              B cells              cuticle 
##                  475                   66                 1270 
##               cortex              medulla                  IRS 
##                  241                  429                  296 
##        proliferative                  ORS            IFE basal 
##                 1489                 1636                 2098 
## IFE granular spinous               HF-SCs            sebocytes 
##                  743                 1386                  213

ORS markers

In this section, we compared ORS to other cells.

group_name = "ORS_vs_all"

aquarius::plot_red_and_blue(sobj,
                            group1 = "ORS",
                            reduction = name2D) +
  ggplot2::labs(title = group_name)

Differential expression

We identify specific markers for each population :

mark = Seurat::FindMarkers(sobj, ident.1 = "ORS")

mark = mark %>%
  dplyr::filter(p_val_adj < 0.05) %>%
  dplyr::arrange(-avg_logFC, pct.1 - pct.2)
mark$gene_name = rownames(mark)

list_results[[group_name]]$mark = mark

dim(mark)
## [1] 970   6
head(mark, n = 20)
##                  p_val avg_logFC pct.1 pct.2     p_val_adj gene_name
## KRT16     0.000000e+00  3.892906 0.905 0.155  0.000000e+00     KRT16
## KRT6B     0.000000e+00  3.166639 0.921 0.275  0.000000e+00     KRT6B
## KRT17     0.000000e+00  2.954873 0.980 0.529  0.000000e+00     KRT17
## KRT6A     0.000000e+00  2.860010 0.752 0.260  0.000000e+00     KRT6A
## S100A2    0.000000e+00  2.635463 0.992 0.789  0.000000e+00    S100A2
## KRT6C     0.000000e+00  2.494914 0.548 0.068  0.000000e+00     KRT6C
## KRT5      0.000000e+00  1.988478 0.993 0.749  0.000000e+00      KRT5
## FABP5     0.000000e+00  1.975885 0.989 0.668  0.000000e+00     FABP5
## GJB6      0.000000e+00  1.912305 0.908 0.525  0.000000e+00      GJB6
## KRT14     0.000000e+00  1.758304 0.992 0.699  0.000000e+00     KRT14
## NDUFA4L2  0.000000e+00  1.721714 0.680 0.212  0.000000e+00  NDUFA4L2
## CST6      0.000000e+00  1.666433 0.384 0.076  0.000000e+00      CST6
## GJB2      0.000000e+00  1.640163 0.826 0.503  0.000000e+00      GJB2
## HSPB1     0.000000e+00  1.630779 0.985 0.835  0.000000e+00     HSPB1
## TM4SF1    0.000000e+00  1.597284 0.801 0.243  0.000000e+00    TM4SF1
## CALML3    0.000000e+00  1.590650 0.958 0.685  0.000000e+00    CALML3
## SDC1      0.000000e+00  1.582781 0.829 0.544  0.000000e+00      SDC1
## S100A16   0.000000e+00  1.547152 0.955 0.720  0.000000e+00   S100A16
## ANXA2     0.000000e+00  1.518822 0.991 0.852  0.000000e+00     ANXA2
## LGALS7B  3.086968e-238  1.508193 0.748 0.465 6.174861e-234   LGALS7B

How many genes enriched in ORS ?

mark_ORS = mark %>%
  dplyr::filter(avg_logFC > 0)

nrow(mark_ORS)
## [1] 336

We cut pct.1 and pct.2 by bins of 0.1 :

mark_ORS$pct.1_cut = cut(mark_ORS$pct.1, breaks = 10)
mark_ORS$pct.2_cut = cut(mark_ORS$pct.2, breaks = 10)

head(mark_ORS)
##        p_val avg_logFC pct.1 pct.2 p_val_adj gene_name     pct.1_cut
## KRT16      0  3.892906 0.905 0.155         0     KRT16 (0.905,0.995]
## KRT6B      0  3.166639 0.921 0.275         0     KRT6B (0.905,0.995]
## KRT17      0  2.954873 0.980 0.529         0     KRT17 (0.905,0.995]
## KRT6A      0  2.860010 0.752 0.260         0     KRT6A (0.726,0.815]
## S100A2     0  2.635463 0.992 0.789         0    S100A2 (0.905,0.995]
## KRT6C      0  2.494914 0.548 0.068         0     KRT6C (0.547,0.637]
##              pct.2_cut
## KRT16      (0.102,0.2]
## KRT6B      (0.2,0.297]
## KRT17    (0.493,0.591]
## KRT6A      (0.2,0.297]
## S100A2   (0.786,0.884]
## KRT6C  (0.00302,0.102]

Visualization

We make a histogram for pct.1, pct.2 and avg_logFC.

hist_wc_fun(mark_ORS, "pct.1")

hist_wc_fun(mark_ORS, "pct.2")

Selection

The best markers have high pct.1 and low pct.2 :

mark_ORS = mark_ORS %>%
  dplyr::filter(pct.1 > 0.6 & pct.2 < 0.3)

list_results[[group_name]]$choosen_ones = mark_ORS

mark_ORS
##          p_val avg_logFC pct.1 pct.2 p_val_adj gene_name     pct.1_cut
## KRT16        0  3.892906 0.905 0.155         0     KRT16 (0.905,0.995]
## KRT6B        0  3.166639 0.921 0.275         0     KRT6B (0.905,0.995]
## KRT6A        0  2.860010 0.752 0.260         0     KRT6A (0.726,0.815]
## NDUFA4L2     0  1.721714 0.680 0.212         0  NDUFA4L2 (0.637,0.726]
## TM4SF1       0  1.597284 0.801 0.243         0    TM4SF1 (0.726,0.815]
## LYPD3        0  1.408274 0.732 0.289         0     LYPD3 (0.726,0.815]
##            pct.2_cut
## KRT16    (0.102,0.2]
## KRT6B    (0.2,0.297]
## KRT6A    (0.2,0.297]
## NDUFA4L2 (0.2,0.297]
## TM4SF1   (0.2,0.297]
## LYPD3    (0.2,0.297]

We visualize expression levels of those genes on the projection :

plot_list = lapply(rownames(mark_ORS), FUN = function(one_gene) {
  Seurat::FeaturePlot(sobj, features = one_gene,
                      reduction = name2D) +
    ggplot2::theme(aspect.ratio = 1) +
    ggplot2::scale_color_gradientn(colors = aquarius::color_gene) +
    Seurat::NoAxes()
})

patchwork::wrap_plots(plot_list, ncol = 3)

IFEb markers

In this section, we compared IFEb to other cells.

group_name = "IFEb_vs_all"

aquarius::plot_red_and_blue(sobj,
                            group1 = "IFE basal",
                            reduction = name2D) +
  ggplot2::labs(title = group_name)

Differential expression

We identify specific markers for each population :

mark = Seurat::FindMarkers(sobj, ident.1 = "IFE basal")

mark = mark %>%
  dplyr::filter(p_val_adj < 0.05) %>%
  dplyr::arrange(-avg_logFC, pct.1 - pct.2)
mark$gene_name = rownames(mark)

list_results[[group_name]]$mark = mark

dim(mark)
## [1] 739   6
head(mark, n = 20)
##                 p_val avg_logFC pct.1 pct.2     p_val_adj gene_name
## KRT15    0.000000e+00 1.2525184 0.929 0.367  0.000000e+00     KRT15
## ATP1B3   0.000000e+00 1.2365428 0.973 0.628  0.000000e+00    ATP1B3
## CCL2     0.000000e+00 1.1973508 0.506 0.056  0.000000e+00      CCL2
## DST      0.000000e+00 1.1908763 0.981 0.352  0.000000e+00       DST
## IMPA2    0.000000e+00 1.0522498 0.924 0.455  0.000000e+00     IMPA2
## COL17A1  0.000000e+00 0.9568857 0.923 0.299  0.000000e+00   COL17A1
## TXNIP    0.000000e+00 0.9062837 0.955 0.547  0.000000e+00     TXNIP
## S100A9   0.000000e+00 0.9041040 0.691 0.231  0.000000e+00    S100A9
## ZFP36L2  0.000000e+00 0.8729918 0.968 0.655  0.000000e+00   ZFP36L2
## IFITM3   0.000000e+00 0.8616994 0.909 0.433  0.000000e+00    IFITM3
## NEAT1    0.000000e+00 0.8281953 0.956 0.672  0.000000e+00     NEAT1
## MOXD1    0.000000e+00 0.8157750 0.764 0.126  0.000000e+00     MOXD1
## CEBPD    0.000000e+00 0.8026200 0.886 0.439  0.000000e+00     CEBPD
## AQP3     0.000000e+00 0.7900901 0.796 0.263  0.000000e+00      AQP3
## PTN     5.159311e-271 0.7884902 0.567 0.234 1.032017e-266       PTN
## ALDH3A1  0.000000e+00 0.7620031 0.607 0.087  0.000000e+00   ALDH3A1
## ARL4A    0.000000e+00 0.7563103 0.874 0.504  0.000000e+00     ARL4A
## GPX2     0.000000e+00 0.7468617 0.633 0.112  0.000000e+00      GPX2
## LIMA1    0.000000e+00 0.7441636 0.893 0.379  0.000000e+00     LIMA1
## FST      0.000000e+00 0.7440017 0.513 0.064  0.000000e+00       FST

How many genes enriched in IFEb ?

mark_IFEb = mark %>%
  dplyr::filter(avg_logFC > 0)

nrow(mark_IFEb)
## [1] 275

We cut pct.1 and pct.2 by bins of 0.1 :

mark_IFEb$pct.1_cut = cut(mark_IFEb$pct.1, breaks = 10)
mark_IFEb$pct.2_cut = cut(mark_IFEb$pct.2, breaks = 10)

head(mark_IFEb)
##         p_val avg_logFC pct.1 pct.2 p_val_adj gene_name     pct.1_cut
## KRT15       0 1.2525184 0.929 0.367         0     KRT15 (0.911,0.999]
## ATP1B3      0 1.2365428 0.973 0.628         0    ATP1B3 (0.911,0.999]
## CCL2        0 1.1973508 0.506 0.056         0      CCL2 (0.479,0.566]
## DST         0 1.1908763 0.981 0.352         0       DST (0.911,0.999]
## IMPA2       0 1.0522498 0.924 0.455         0     IMPA2 (0.911,0.999]
## COL17A1     0 0.9568857 0.923 0.299         0   COL17A1 (0.911,0.999]
##             pct.2_cut
## KRT15   (0.309,0.407]
## ATP1B3  (0.603,0.701]
## CCL2    (0.013,0.112]
## DST     (0.309,0.407]
## IMPA2   (0.407,0.505]
## COL17A1  (0.21,0.309]

Visualization

We make a histogram for pct.1, pct.2 and avg_logFC.

hist_wc_fun(mark_IFEb, "pct.1")

hist_wc_fun(mark_IFEb, "pct.2")

Selection

The best markers have high pct.1 and low pct.2 :

mark_IFEb = mark_IFEb %>%
  dplyr::filter(pct.1 > 0.6 & pct.2 < 0.2)

list_results[[group_name]]$choosen_ones = mark_IFEb

mark_IFEb
##         p_val avg_logFC pct.1 pct.2 p_val_adj gene_name     pct.1_cut
## MOXD1       0 0.8157750 0.764 0.126         0     MOXD1 (0.738,0.825]
## ALDH3A1     0 0.7620031 0.607 0.087         0   ALDH3A1 (0.566,0.652]
## GPX2        0 0.7468617 0.633 0.112         0      GPX2 (0.566,0.652]
## AHNAK2      0 0.7113339 0.749 0.184         0    AHNAK2 (0.738,0.825]
## CDH13       0 0.6071029 0.741 0.158         0     CDH13 (0.738,0.825]
## LAMB3       0 0.6026591 0.740 0.163         0     LAMB3 (0.738,0.825]
## S100A8      0 0.5772416 0.659 0.196         0    S100A8 (0.652,0.738]
## NBL1        0 0.4801919 0.627 0.159         0      NBL1 (0.566,0.652]
## CCDC3       0 0.4355107 0.601 0.182         0     CCDC3 (0.566,0.652]
## SPARC       0 0.4180143 0.607 0.180         0     SPARC (0.566,0.652]
##             pct.2_cut
## MOXD1    (0.112,0.21]
## ALDH3A1 (0.013,0.112]
## GPX2    (0.013,0.112]
## AHNAK2   (0.112,0.21]
## CDH13    (0.112,0.21]
## LAMB3    (0.112,0.21]
## S100A8   (0.112,0.21]
## NBL1     (0.112,0.21]
## CCDC3    (0.112,0.21]
## SPARC    (0.112,0.21]

We visualize expression levels of those genes on the projection :

plot_list = lapply(rownames(mark_IFEb), FUN = function(one_gene) {
  Seurat::FeaturePlot(sobj, features = one_gene,
                      reduction = name2D) +
    ggplot2::theme(aspect.ratio = 1) +
    ggplot2::scale_color_gradientn(colors = aquarius::color_gene) +
    Seurat::NoAxes()
})

patchwork::wrap_plots(plot_list, ncol = 3)

Save

We save the list of results :

saveRDS(list_results, file = paste0(out_dir, "/ors_ifeb_markers.rds"))

We also save as XLSX file :

list_results2 = list(ORS_vs_all = list_results$ORS_vs_all$mark,
                     ORS_vs_all_selection = list_results$ORS_vs_all$choosen_ones,
                     IFEb_vs_all = list_results$IFEb_vs_all$mark,
                     IFEb_vs_all_selection = list_results$IFEb_vs_all$choosen_ones)

openxlsx::write.xlsx(list_results2, file = paste0(out_dir, "/ors_vs_ifeb_markers.xlsx"))

R Session

show
## R version 3.6.3 (2020-02-29)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 20.04.6 LTS
## 
## Matrix products: default
## BLAS:   /usr/local/lib/R/lib/libRblas.so
## LAPACK: /usr/local/lib/R/lib/libRlapack.so
## 
## locale:
## [1] C
## 
## attached base packages:
## [1] grid      stats     graphics  grDevices utils     datasets  methods  
## [8] base     
## 
## other attached packages:
## [1] ComplexHeatmap_2.14.0 ggplot2_3.3.5         patchwork_1.1.2      
## [4] dplyr_1.0.7          
## 
## loaded via a namespace (and not attached):
##   [1] softImpute_1.4              graphlayouts_0.7.0         
##   [3] pbapply_1.4-2               lattice_0.20-41            
##   [5] haven_2.3.1                 vctrs_0.3.8                
##   [7] usethis_2.0.1               dynwrap_1.2.1              
##   [9] blob_1.2.1                  survival_3.2-13            
##  [11] prodlim_2019.11.13          dynutils_1.0.5             
##  [13] later_1.3.0                 DBI_1.1.1                  
##  [15] R.utils_2.11.0              SingleCellExperiment_1.8.0 
##  [17] rappdirs_0.3.3              uwot_0.1.8                 
##  [19] dqrng_0.2.1                 jpeg_0.1-8.1               
##  [21] zlibbioc_1.32.0             pspline_1.0-18             
##  [23] pcaMethods_1.78.0           mvtnorm_1.1-1              
##  [25] htmlwidgets_1.5.4           GlobalOptions_0.1.2        
##  [27] future_1.22.1               UpSetR_1.4.0               
##  [29] laeken_0.5.2                leiden_0.3.3               
##  [31] clustree_0.4.3              parallel_3.6.3             
##  [33] scater_1.14.6               irlba_2.3.3                
##  [35] markdown_1.1                DEoptimR_1.0-9             
##  [37] tidygraph_1.1.2             Rcpp_1.0.9                 
##  [39] readr_2.0.2                 KernSmooth_2.23-17         
##  [41] carrier_0.1.0               promises_1.1.0             
##  [43] gdata_2.18.0                DelayedArray_0.12.3        
##  [45] limma_3.42.2                graph_1.64.0               
##  [47] RcppParallel_5.1.4          Hmisc_4.4-0                
##  [49] fs_1.5.2                    RSpectra_0.16-0            
##  [51] fastmatch_1.1-0             ranger_0.12.1              
##  [53] digest_0.6.25               png_0.1-7                  
##  [55] sctransform_0.2.1           cowplot_1.0.0              
##  [57] DOSE_3.12.0                 here_1.0.1                 
##  [59] TInGa_0.0.0.9000            ggraph_2.0.3               
##  [61] pkgconfig_2.0.3             GO.db_3.10.0               
##  [63] DelayedMatrixStats_1.8.0    gower_0.2.1                
##  [65] ggbeeswarm_0.6.0            iterators_1.0.12           
##  [67] DropletUtils_1.6.1          reticulate_1.26            
##  [69] clusterProfiler_3.14.3      SummarizedExperiment_1.16.1
##  [71] circlize_0.4.15             beeswarm_0.4.0             
##  [73] GetoptLong_1.0.5            xfun_0.35                  
##  [75] bslib_0.3.1                 zoo_1.8-10                 
##  [77] tidyselect_1.1.0            reshape2_1.4.4             
##  [79] purrr_0.3.4                 ica_1.0-2                  
##  [81] pcaPP_1.9-73                viridisLite_0.3.0          
##  [83] rtracklayer_1.46.0          rlang_1.0.2                
##  [85] hexbin_1.28.1               jquerylib_0.1.4            
##  [87] dyneval_0.9.9               glue_1.4.2                 
##  [89] RColorBrewer_1.1-2          matrixStats_0.56.0         
##  [91] stringr_1.4.0               lava_1.6.7                 
##  [93] europepmc_0.3               DESeq2_1.26.0              
##  [95] recipes_0.1.17              labeling_0.3               
##  [97] httpuv_1.5.2                class_7.3-17               
##  [99] BiocNeighbors_1.4.2         DO.db_2.9                  
## [101] annotate_1.64.0             jsonlite_1.7.2             
## [103] XVector_0.26.0              bit_4.0.4                  
## [105] mime_0.9                    aquarius_0.1.5             
## [107] Rsamtools_2.2.3             gridExtra_2.3              
## [109] gplots_3.0.3                stringi_1.4.6              
## [111] processx_3.5.2              gsl_2.1-6                  
## [113] bitops_1.0-6                cli_3.0.1                  
## [115] batchelor_1.2.4             RSQLite_2.2.0              
## [117] randomForest_4.6-14         tidyr_1.1.4                
## [119] data.table_1.14.2           rstudioapi_0.13            
## [121] org.Mm.eg.db_3.10.0         GenomicAlignments_1.22.1   
## [123] nlme_3.1-147                qvalue_2.18.0              
## [125] scran_1.14.6                locfit_1.5-9.4             
## [127] scDblFinder_1.1.8           listenv_0.8.0              
## [129] ggthemes_4.2.4              gridGraphics_0.5-0         
## [131] R.oo_1.24.0                 dbplyr_1.4.4               
## [133] BiocGenerics_0.32.0         TTR_0.24.2                 
## [135] readxl_1.3.1                lifecycle_1.0.1            
## [137] timeDate_3043.102           ggpattern_0.3.1            
## [139] munsell_0.5.0               cellranger_1.1.0           
## [141] R.methodsS3_1.8.1           proxyC_0.1.5               
## [143] visNetwork_2.0.9            caTools_1.18.0             
## [145] codetools_0.2-16            ggwordcloud_0.5.0          
## [147] Biobase_2.46.0              GenomeInfoDb_1.22.1        
## [149] vipor_0.4.5                 lmtest_0.9-38              
## [151] msigdbr_7.5.1               htmlTable_1.13.3           
## [153] triebeard_0.3.0             lsei_1.2-0                 
## [155] xtable_1.8-4                ROCR_1.0-7                 
## [157] BiocManager_1.30.10         scatterplot3d_0.3-41       
## [159] abind_1.4-5                 farver_2.0.3               
## [161] parallelly_1.28.1           RANN_2.6.1                 
## [163] askpass_1.1                 GenomicRanges_1.38.0       
## [165] RcppAnnoy_0.0.16            tibble_3.1.5               
## [167] ggdendro_0.1-20             cluster_2.1.0              
## [169] future.apply_1.5.0          Seurat_3.1.5               
## [171] dendextend_1.15.1           Matrix_1.3-2               
## [173] ellipsis_0.3.2              prettyunits_1.1.1          
## [175] lubridate_1.7.9             ggridges_0.5.2             
## [177] igraph_1.2.5                RcppEigen_0.3.3.7.0        
## [179] fgsea_1.12.0                remotes_2.4.2              
## [181] scBFA_1.0.0                 destiny_3.0.1              
## [183] VIM_6.1.1                   testthat_3.1.0             
## [185] htmltools_0.5.2             BiocFileCache_1.10.2       
## [187] yaml_2.2.1                  utf8_1.1.4                 
## [189] plotly_4.9.2.1              XML_3.99-0.3               
## [191] ModelMetrics_1.2.2.2        e1071_1.7-3                
## [193] foreign_0.8-76              withr_2.5.0                
## [195] fitdistrplus_1.0-14         BiocParallel_1.20.1        
## [197] xgboost_1.4.1.1             bit64_4.0.5                
## [199] foreach_1.5.0               robustbase_0.93-9          
## [201] Biostrings_2.54.0           GOSemSim_2.13.1            
## [203] rsvd_1.0.3                  memoise_2.0.0              
## [205] evaluate_0.18               forcats_0.5.0              
## [207] rio_0.5.16                  geneplotter_1.64.0         
## [209] tzdb_0.1.2                  caret_6.0-86               
## [211] ps_1.6.0                    DiagrammeR_1.0.6.1         
## [213] curl_4.3                    fdrtool_1.2.15             
## [215] fansi_0.4.1                 highr_0.8                  
## [217] urltools_1.7.3              xts_0.12.1                 
## [219] GSEABase_1.48.0             acepack_1.4.1              
## [221] edgeR_3.28.1                checkmate_2.0.0            
## [223] scds_1.2.0                  cachem_1.0.6               
## [225] npsurv_0.4-0                babelgene_22.3             
## [227] rjson_0.2.20                openxlsx_4.1.5             
## [229] ggrepel_0.9.1               clue_0.3-60                
## [231] rprojroot_2.0.2             stabledist_0.7-1           
## [233] tools_3.6.3                 sass_0.4.0                 
## [235] nichenetr_1.1.1             magrittr_2.0.1             
## [237] RCurl_1.98-1.2              proxy_0.4-24               
## [239] car_3.0-11                  ape_5.3                    
## [241] ggplotify_0.0.5             xml2_1.3.2                 
## [243] httr_1.4.2                  assertthat_0.2.1           
## [245] rmarkdown_2.18              boot_1.3-25                
## [247] globals_0.14.0              R6_2.4.1                   
## [249] Rhdf5lib_1.8.0              nnet_7.3-14                
## [251] RcppHNSW_0.2.0              progress_1.2.2             
## [253] genefilter_1.68.0           statmod_1.4.34             
## [255] gtools_3.8.2                shape_1.4.6                
## [257] HDF5Array_1.14.4            BiocSingular_1.2.2         
## [259] rhdf5_2.30.1                splines_3.6.3              
## [261] AUCell_1.8.0                carData_3.0-4              
## [263] colorspace_1.4-1            generics_0.1.0             
## [265] stats4_3.6.3                base64enc_0.1-3            
## [267] dynfeature_1.0.0            smoother_1.1               
## [269] gridtext_0.1.1              pillar_1.6.3               
## [271] tweenr_1.0.1                sp_1.4-1                   
## [273] ggplot.multistats_1.0.0     rvcheck_0.1.8              
## [275] GenomeInfoDbData_1.2.2      plyr_1.8.6                 
## [277] gtable_0.3.0                zip_2.2.0                  
## [279] knitr_1.41                  latticeExtra_0.6-29        
## [281] biomaRt_2.42.1              IRanges_2.20.2             
## [283] fastmap_1.1.0               ADGofTest_0.3              
## [285] copula_1.0-0                doParallel_1.0.15          
## [287] AnnotationDbi_1.48.0        vcd_1.4-8                  
## [289] babelwhale_1.0.1            openssl_1.4.1              
## [291] scales_1.1.1                backports_1.2.1            
## [293] S4Vectors_0.24.4            ipred_0.9-12               
## [295] enrichplot_1.6.1            hms_1.1.1                  
## [297] ggforce_0.3.1               Rtsne_0.15                 
## [299] shiny_1.7.1                 numDeriv_2016.8-1.1        
## [301] polyclip_1.10-0             lazyeval_0.2.2             
## [303] Formula_1.2-3               tsne_0.1-3                 
## [305] crayon_1.3.4                MASS_7.3-54                
## [307] pROC_1.16.2                 viridis_0.5.1              
## [309] dynparam_1.0.0              rpart_4.1-15               
## [311] zinbwave_1.8.0              compiler_3.6.3             
## [313] ggtext_0.1.0
LS0tCnRpdGxlOiAiSFMgcHJvamVjdCIKc3VidGl0bGU6ICJJRkUgYmFzYWwgYW5kIE9SUyBzaWduYXR1cmUiCmF1dGhvcjogIkF1ZHJleSIKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJVktJW0tJWQnKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQotLS0KCjxzdHlsZT4KYm9keSB7CnRleHQtYWxpZ246IGp1c3RpZnl9Cjwvc3R5bGU+Cgo8IS0tIEF1dG9tYXRpY2FsbHkgY29tcHV0ZXMgYW5kIHByaW50cyBpbiB0aGUgb3V0cHV0IHRoZSBydW5uaW5nIHRpbWUgZm9yIGFueSBjb2RlIGNodW5rIC0tPgpgYGB7ciwgZWNobz1GQUxTRX0KIyBodHRwczovL2dpdGh1Yi5jb20vcnN0dWRpby9ybWFya2Rvd24vaXNzdWVzLzE0NTMKaG9va3MgPSBrbml0cjo6a25pdF9ob29rcyRnZXQoKQpob29rX2ZvbGRhYmxlID0gZnVuY3Rpb24odHlwZSkgewogIGZvcmNlKHR5cGUpCiAgZnVuY3Rpb24oeCwgb3B0aW9ucykgewogICAgcmVzID0gaG9va3NbW3R5cGVdXSh4LCBvcHRpb25zKQogICAgCiAgICBpZiAoaXNGQUxTRShvcHRpb25zW1twYXN0ZTAoImZvbGRfIiwgdHlwZSldXSkpIHJldHVybihyZXMpCiAgICAKICAgIHBhc3RlMCgKICAgICAgIjxkZXRhaWxzPjxzdW1tYXJ5PiIsICJzaG93IiwgIjwvc3VtbWFyeT5cblxuIiwKICAgICAgcmVzLAogICAgICAiXG5cbjwvZGV0YWlscz4iCiAgICApCiAgfQp9CmtuaXRyOjprbml0X2hvb2tzJHNldCgKICBvdXRwdXQgPSBob29rX2ZvbGRhYmxlKCJvdXRwdXQiKSwKICBwbG90ID0gaG9va19mb2xkYWJsZSgicGxvdCIpLAogIHRpbWVfaXQgPSBsb2NhbCh7CiAgICBub3cgPSBOVUxMCiAgICBmdW5jdGlvbihiZWZvcmUsIG9wdGlvbnMpIHsKICAgICAgaWYgKG9wdGlvbnMkdGltZV9pdCkgewogICAgICAgIGlmIChiZWZvcmUpIHsKICAgICAgICAgIG5vdyA8PSBTeXMudGltZSgpCiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHJlcyA9IGRpZmZ0aW1lKFN5cy50aW1lKCksIG5vdywgdW5pdHMgPSAic2VjcyIpCiAgICAgICAgICBwYXN0ZSgiKFRpbWUgdG8gcnVuIDoiLCByb3VuZChyZXMsIGRpZ2l0cyA9IDIpLCAicykiKQogICAgICAgIH0KICAgICAgfQogICAgfQogIH0pCikKYGBgCgo8IS0tIFNldCBkZWZhdWx0IHBhcmFtZXRlcnMgZm9yIGFsbCBjaHVua3MgLS0+CmBgYHtyLCBzZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQpzZXQuc2VlZCgxMzM3TCkKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAjIGRpc3BsYXkgY29kZQogICAgICAgICAgICAgICAgICAgICAgIyBkaXNwbGF5IGNodW5rIG91dHB1dAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgZm9sZF9vdXRwdXQgPSBGQUxTRSwgIyB1c2VmdWxsIGZvciBzZXNzaW9uSW5mbygpCiAgICAgICAgICAgICAgICAgICAgICBmb2xkX3Bsb3QgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgIyBmaWd1cmUgc2V0dGluZ3MKICAgICAgICAgICAgICAgICAgICAgIGZpZy5hbGlnbiA9ICdjZW50ZXInLAogICAgICAgICAgICAgICAgICAgICAgZmlnLndpZHRoID0gMjAsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuaGVpZ2h0ID0gMTUsCiAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICMgc29tZXRoaW5nIGFib3V0IHNlZWQsIGNodW5rIGFuZCBSbWFya2Rvd24gY29tcGlsYXRpb24KICAgICAgICAgICAgICAgICAgICAgICMgaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMzk0MTcwMDMvbG9uZy12ZWN0b3JzLW5vdC1zdXBwb3J0ZWQteWV0LWVycm9yLWluLXJtZC1idXQtbm90LWluLXItc2NyaXB0CiAgICAgICAgICAgICAgICAgICAgICAjIGNhY2hlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIGNhY2hlLmxhenkgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICMgYWRkIHJ1bnRpbWUgYWZ0ZXIgY2h1bmsKICAgICAgICAgICAgICAgICAgICAgIHRpbWVfaXQgPSBGQUxTRSkKYGBgCgoKVGhpcyBmaWxlIGlzIHVzZWQgdG8gaWRlbnRpZnkgc3BlY2lmaWMgbWFya2VycyBmb3IgT1JTIGFuZCBJRkUgYmFzYWwuCgpgYGB7ciBsaWJyYXJ5fQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKQoKLmxpYlBhdGhzKCkKYGBgCgojIFByZXBhcmF0aW9uCgpJbiB0aGlzIHNlY3Rpb24sIHdlIHNldCB0aGUgZ2xvYmFsIHNldHRpbmdzIG9mIHRoZSBhbmFseXNpcy4gV2Ugd2lsbCBzdG9yZSBkYXRhIHRoZXJlIDoKCmBgYHtyIG91dF9kaXJ9Cm91dF9kaXIgPSAiLiIKYGBgCgpXZSBsb2FkIHRoZSBkYXRhc2V0IDoKCmBgYHtyIGxvYWRfc29ian0Kc29iaiA9IHJlYWRSRFMocGFzdGUwKG91dF9kaXIsICIvaHNfaGRfc29iai5yZHMiKSkKc29iagpgYGAKCldlIGxvYWQgdGhlIHNhbXBsZSBpbmZvcm1hdGlvbiA6CgpgYGB7ciBjdXN0b21fcGFsZXR0ZV9zYW1wbGUsIGZpZy53aWR0aCA9IDYsIGZpZy5oZWlnaHQgPSA2fQpzYW1wbGVfaW5mbyA9IHJlYWRSRFMocGFzdGUwKG91dF9kaXIsICIvLi4vMV9tZXRhZGF0YS9oc19oZF9zYW1wbGVfaW5mby5yZHMiKSkKcHJvamVjdF9uYW1lc19vaSA9IHNhbXBsZV9pbmZvJHByb2plY3RfbmFtZQoKZ3JhcGhpY3M6OnBpZShyZXAoMSwgbnJvdyhzYW1wbGVfaW5mbykpLAogICAgICAgICAgICAgIGNvbCA9IHNhbXBsZV9pbmZvJGNvbG9yLAogICAgICAgICAgICAgIGxhYmVscyA9IHNhbXBsZV9pbmZvJHByb2plY3RfbmFtZSkKYGBgCgpIZXJlIGFyZSBjdXN0b20gY29sb3JzIGZvciBlYWNoIGNlbGwgdHlwZSA6CgpgYGB7ciBjb2xvcl9tYXJrZXJzLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDEuMiwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmNvbG9yX21hcmtlcnMgPSByZWFkUkRTKHBhc3RlMChvdXRfZGlyLCAiLy4uLzFfbWV0YWRhdGEvaHNfaGRfY29sb3JfbWFya2Vycy5yZHMiKSkKCmRhdGEuZnJhbWUoY2VsbF90eXBlID0gbmFtZXMoY29sb3JfbWFya2VycyksCiAgICAgICAgICAgY29sb3IgPSB1bmxpc3QoY29sb3JfbWFya2VycykpICU+JQogIGdncGxvdDI6OmdncGxvdCguLCBhZXMoeCA9IGNlbGxfdHlwZSwgeSA9IDAsIGZpbGwgPSBjZWxsX3R5cGUpKSArCiAgZ2dwbG90Mjo6Z2VvbV9wb2ludChwY2ggPSAyMSwgc2l6ZSA9IDUpICsKICBnZ3Bsb3QyOjpzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB1bmxpc3QoY29sb3JfbWFya2VycyksIGJyZWFrcyA9IG5hbWVzKGNvbG9yX21hcmtlcnMpKSArCiAgZ2dwbG90Mjo6dGhlbWVfY2xhc3NpYygpICsKICBnZ3Bsb3QyOjp0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwLCBoanVzdCA9IDEpKQpgYGAKClRoaXMgaXMgdGhlIHByb2plY3Rpb24gb2YgaW50ZXJlc3QgOgoKYGBge3IgbmFtZTJEfQpuYW1lMkQgPSAiaGFybW9ueV8zOF90c25lIgpgYGAKCldlIGRlc2lnbiBhIGN1c3RvbSBmdW5jdGlvbiB0byBtYWtlIGEgaGlzdG9ncmFtIGFuZCBhIHdvcmRjbG91ZCB0byB2aXN1YWxpemUgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIDoKCmBgYHtyIGhpc3Rfd2NfZnVuLCBjbGFzcy5zb3VjZSA9ICJmb2xkLWhpZGUifQpoaXN0X3djX2Z1biA9IGZ1bmN0aW9uKG1hcmssIGNvbCkgewogIGN1dF9jb2xvcnMgPSBjKCJmaXJlYnJpY2s0IiwgImZpcmVicmljazIiLCAiaW5kaWFucmVkMSIsICJkYXJrc2FsbW9uIiwKICAgICAgICAgICAgICAgICAibGlnaHRwaW5rIiwgImdyYXk1MCIsICJraGFraTMiLCAiZGFya29saXZlZ3JlZW4xIiwKICAgICAgICAgICAgICAgICAib2xpdmVkcmFiMSIsICJjaGFydHJldXNlMiIsICJjaGFydHJldXNlNCIpCiAgY3V0X2NvbG9yc19jb250ID0gYyhyZXYoUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKG5hbWUgPSAiUmVkcyIsIG4gPSA5KVtjKDU6OSldKSwKICAgICAgICAgICAgICAgICAgICAgIFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbChuYW1lID0gIkdyZWVucyIsIG4gPSA5KVtjKDU6OSldKQogIAogIGlmIChjb2wgPT0gInBjdC4xIikgewogICAgbWFyayRwY3QgPSBtYXJrJHBjdC4xCiAgICBtYXJrJHBjdF9jdXQgPSBtYXJrJHBjdC4xX2N1dAogIH0gZWxzZSBpZiAoY29sID09ICJwY3QuMiIpIHsKICAgIG1hcmskcGN0ID0gbWFyayRwY3QuMgogICAgbWFyayRwY3RfY3V0ID0gbWFyayRwY3QuMl9jdXQKICAgIGN1dF9jb2xvcnMgPSByZXYoY3V0X2NvbG9ycykKICAgIGN1dF9jb2xvcnNfY29udCA9IHJldihjdXRfY29sb3JzX2NvbnQpCiAgfSBlbHNlIHsKICAgIHN0b3AoImNvbCBtdXN0IGJlIGVpdGhlciBwY3QuMSBvciBwY3QuMiIpCiAgfQogIAogIHBfaGlzdCA9IGdncGxvdDI6OmdncGxvdChtYXJrLCBtYXBwaW5nID0gYWVzKHggPSBhdmdfbG9nRkMsIGZpbGwgPSBwY3RfY3V0KSkgKwogICAgZ2dwbG90Mjo6Z2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjA1KSArCiAgICBnZ3Bsb3QyOjpzY2FsZV9maWxsX21hbnVhbChicmVha3MgPSBsZXZlbHMobWFyayRwY3RfY3V0KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGN1dF9jb2xvcnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gcGFzdGUwKGNvbCwgIl9jdXQiKSkgKwogICAgZ2dwbG90Mjo6dGhlbWVfY2xhc3NpYygpCiAgCiAgcF93YyA9IGdncGxvdDI6OmdncGxvdChtYXJrLCBhZXMobGFiZWwgPSBnZW5lX25hbWUsIHNpemUgPSBhdmdfbG9nRkMsIGNvbG9yID0gcGN0KSkgKwogICAgZ2d3b3JkY2xvdWQ6Omdlb21fdGV4dF93b3JkY2xvdWRfYXJlYShzaG93LmxlZ2VuZCA9IFRSVUUsIHNlZWQgPSAxKSArCiAgICBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gY3V0X2NvbG9yc19jb250LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSBjb2wpICsKICAgIGdncGxvdDI6OnNjYWxlX3NpemVfYXJlYShtYXhfc2l6ZSA9IDUpICsKICAgIGdncGxvdDI6OnRoZW1lX21pbmltYWwoKSArCiAgICBnZ3Bsb3QyOjpndWlkZXMoc2l6ZSA9ICJub25lIikKICAKICBwID0gcGF0Y2h3b3JrOjp3cmFwX3Bsb3RzKHBfaGlzdCwgcF93YywgbnJvdyA9IDEpCiAgCiAgcmV0dXJuKHApCn0KYGBgCgoKIyBWaXN1YWxpemF0aW9uCgojIyBHZW5lIGV4cHJlc3Npb24KCldlIHZpc3VhbGl6ZSBnZW5lIGV4cHJlc3Npb24gZm9yIHNvbWUgbWFya2VycyA6CgpgYGB7ciBwbG90X2xpc3RfZmVhdHVyZXMsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gNH0KZmVhdHVyZXMgPSBjKCJwZXJjZW50Lm10IiwgInBlcmNlbnQucmIiLCAibkZlYXR1cmVfUk5BIikKCnBsb3RfbGlzdCA9IGxhcHBseShmZWF0dXJlcywgRlVOID0gZnVuY3Rpb24ob25lX2dlbmUpIHsKICBTZXVyYXQ6OkZlYXR1cmVQbG90KHNvYmosIGZlYXR1cmVzID0gb25lX2dlbmUsCiAgICAgICAgICAgICAgICAgICAgICByZWR1Y3Rpb24gPSBuYW1lMkQpICsKICAgIGdncGxvdDI6OnRoZW1lKGFzcGVjdC5yYXRpbyA9IDEpICsKICAgIGdncGxvdDI6OnNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBhcXVhcml1czo6Y29sb3JfZ2VuZSkgKwogICAgU2V1cmF0OjpOb0F4ZXMoKQp9KQoKcGF0Y2h3b3JrOjp3cmFwX3Bsb3RzKHBsb3RfbGlzdCwgbmNvbCA9IDMpCmBgYApDbHVzdGVyIHR5cGUgQ2x1c3RlcnMgYW5kIGNlbGwgdHlwZQoKV2UgdmlzdWFsaXplIGNsdXN0ZXJzIGFuZCBjZWxsIHR5cGUgOgoKYGBge3Igc2VlX2NsdXN0ZXJpbmcsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gNH0KY2x1c3Rlcl9wbG90ID0gU2V1cmF0OjpEaW1QbG90KHNvYmosIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWR1Y3Rpb24gPSBuYW1lMkQsIGxhYmVsID0gVFJVRSkgKwogIGdncGxvdDI6OmxhYnModGl0bGUgPSAiQ2x1c3RlciBJRCIpICsKICBTZXVyYXQ6Ok5vQXhlcygpICsKICBnZ3Bsb3QyOjp0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQoKY2VsbF90eXBlX3Bsb3QgPSBTZXVyYXQ6OkRpbVBsb3Qoc29iaiwgZ3JvdXAuYnkgPSAiY2VsbF90eXBlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVkdWN0aW9uID0gbmFtZTJELCBsYWJlbCA9IEZBTFNFKSArCiAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9yX21hcmtlcnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IG5hbWVzKGNvbG9yX21hcmtlcnMpKSArCiAgZ2dwbG90Mjo6bGFicyh0aXRsZSA9ICJDZWxsIHR5cGUiKSArCiAgU2V1cmF0OjpOb0F4ZXMoKSArCiAgZ2dwbG90Mjo6dGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKCmNlbGxfdHlwZV9wbG90IHwgY2x1c3Rlcl9wbG90CmBgYAoKV2Ugc3VtbWFyaXplIG1ham9yIGNlbGwgdHlwZSBieSBjbHVzdGVyIDoKCmBgYHtyIGNlbGxfdHlwZV9jbHVzdGVyc30KY2VsbF90eXBlX2NsdXN0ZXJzID0gc29iakBtZXRhLmRhdGFbLCBjKCJjZWxsX3R5cGUiLCAic2V1cmF0X2NsdXN0ZXJzIildICU+JQogIHRhYmxlKCkgJT4lCiAgcHJvcC50YWJsZSguLCBtYXJnaW4gPSAyKSAlPiUKICBhcHBseSguLCAyLCB3aGljaC5tYXgpCmNlbGxfdHlwZV9jbHVzdGVycyA9IHNldE5hbWVzKGxldmVscyhzb2JqJGNlbGxfdHlwZSlbY2VsbF90eXBlX2NsdXN0ZXJzXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm0gPSBuYW1lcyhjZWxsX3R5cGVfY2x1c3RlcnMpKQoKYGBgCgpXZSBkZWZpbmUgY2x1c3RlciB0eXBlIDoKCmBgYHtyIHRhYmxlX2NsdXN0ZXJfdHlwZX0Kc29iaiRjbHVzdGVyX3R5cGUgPSBjZWxsX3R5cGVfY2x1c3RlcnNbc29iaiRzZXVyYXRfY2x1c3RlcnNdICU+JQogIGFzLmZhY3RvcigpCnRhYmxlKHNvYmokY2x1c3Rlcl90eXBlLCBzb2JqJGNlbGxfdHlwZSkKYGBgCgpXZSBjb21wYXJlIGNsdXN0ZXIgYW5ub3RhdGlvbiBhbmQgY2VsbCB0eXBlIGFubm90YXRpb24gOgoKYGBge3Igc2VlX2NsdXN0ZXJfdHlwZSwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA1fQpjZWxsX3R5cGVfcGxvdAoKcDIgPSBTZXVyYXQ6OkRpbVBsb3Qoc29iaiwgZ3JvdXAuYnkgPSAiY2x1c3Rlcl90eXBlIiwKICAgICAgICAgICAgICAgICAgICAgcmVkdWN0aW9uID0gbmFtZTJELCBjb2xzID0gY29sb3JfbWFya2VycykgKwogIGdncGxvdDI6OmxhYnModGl0bGUgPSAiQ2x1c3RlciB0eXBlIikgKwogIFNldXJhdDo6Tm9BeGVzKCkgKwogIGdncGxvdDI6OnRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCgpwYXRjaHdvcms6OndyYXBfcGxvdHMoY2VsbF90eXBlX3Bsb3QsIHAyLCBndWlkZXMgPSAiY29sbGVjdCIpCmBgYAoKVGhlcmUgaXMgbWlzLWFubm90YXRpb24sIHNvIHdlIGtlZXAgdGhlIHNpbmdsZS1jZWxsIGxldmVsIGNlbGwgdHlwZSBhbm5vdGF0aW9uLgoKIyBEaWZmZXJlbnRpYWwgZXhwcmVzc2lvbgoKSW4gdGhpcyBzZWN0aW9uLCB3ZSBwZXJmb3JtIERFIGJldHdlZW4gaW50ZXJmb2xsaWN1bGFyIGVwaWRlcm1pcyAoSUZFKSBiYXNhbCBvciBvdXRlciByb290IHNoZWF0aCAoT1JTKSwgYW5kIGFsbCByZW1haW5pbmcgY2VsbHMuIFdlIHNhdmUgdGhlIHJlc3VsdHMgaW4gYSBsaXN0IDoKCmBgYHtyIGxpc3RfcmVzdWx0c30KbGlzdF9yZXN1bHRzID0gbGlzdCgpCmBgYAoKV2UgY2hhbmdlIGNlbGwgaWRlbnRpdGllcyB0byBjZWxsIHR5cGUgOgoKYGBge3IgaWRlbnRfY2VsbF90eXBlfQpTZXVyYXQ6OklkZW50cyhzb2JqKSA9IHNvYmokY2VsbF90eXBlCgp0YWJsZShTZXVyYXQ6OklkZW50cyhzb2JqKSkKYGBgCgojIyBPUlMgbWFya2VycwoKSW4gdGhpcyBzZWN0aW9uLCB3ZSBjb21wYXJlZCBPUlMgdG8gb3RoZXIgY2VsbHMuCgpgYGB7ciBzZWVfT1JTLCBmaWcud2lkdGggPSA2LCBmaWcuaGVpZ2h0ID0gNH0KZ3JvdXBfbmFtZSA9ICJPUlNfdnNfYWxsIgoKYXF1YXJpdXM6OnBsb3RfcmVkX2FuZF9ibHVlKHNvYmosCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cDEgPSAiT1JTIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZHVjdGlvbiA9IG5hbWUyRCkgKwogIGdncGxvdDI6OmxhYnModGl0bGUgPSBncm91cF9uYW1lKQpgYGAKCiMjIyBEaWZmZXJlbnRpYWwgZXhwcmVzc2lvbgoKV2UgaWRlbnRpZnkgc3BlY2lmaWMgbWFya2VycyBmb3IgZWFjaCBwb3B1bGF0aW9uIDoKCmBgYHtyIGRlX09SU30KbWFyayA9IFNldXJhdDo6RmluZE1hcmtlcnMoc29iaiwgaWRlbnQuMSA9ICJPUlMiKQoKbWFyayA9IG1hcmsgJT4lCiAgZHBseXI6OmZpbHRlcihwX3ZhbF9hZGogPCAwLjA1KSAlPiUKICBkcGx5cjo6YXJyYW5nZSgtYXZnX2xvZ0ZDLCBwY3QuMSAtIHBjdC4yKQptYXJrJGdlbmVfbmFtZSA9IHJvd25hbWVzKG1hcmspCgpsaXN0X3Jlc3VsdHNbW2dyb3VwX25hbWVdXSRtYXJrID0gbWFyawoKZGltKG1hcmspCmhlYWQobWFyaywgbiA9IDIwKQpgYGAKCkhvdyBtYW55IGdlbmVzIGVucmljaGVkIGluIE9SUyA/CgpgYGB7ciBtYXJrX09SU30KbWFya19PUlMgPSBtYXJrICU+JQogIGRwbHlyOjpmaWx0ZXIoYXZnX2xvZ0ZDID4gMCkKCm5yb3cobWFya19PUlMpCmBgYAoKV2UgY3V0IHBjdC4xIGFuZCBwY3QuMiBieSBiaW5zIG9mIDAuMSA6CgpgYGB7ciBtYXJrX2N1dF9PUlN9Cm1hcmtfT1JTJHBjdC4xX2N1dCA9IGN1dChtYXJrX09SUyRwY3QuMSwgYnJlYWtzID0gMTApCm1hcmtfT1JTJHBjdC4yX2N1dCA9IGN1dChtYXJrX09SUyRwY3QuMiwgYnJlYWtzID0gMTApCgpoZWFkKG1hcmtfT1JTKQpgYGAKCgojIyMgVmlzdWFsaXphdGlvbgoKV2UgbWFrZSBhIGhpc3RvZ3JhbSBmb3IgYHBjdC4xYCwgYHBjdC4yYCBhbmQgYGF2Z19sb2dGQ2AuCgpgYGB7ciBoaXN0X2ZjX09SU18xLCBmaWcud2lkdGggPSAxMywgZmlnLmhlaWdodCA9IDV9Cmhpc3Rfd2NfZnVuKG1hcmtfT1JTLCAicGN0LjEiKQpgYGAKCmBgYHtyIGhpc3RfZmNfT1JTXzIsIGZpZy53aWR0aCA9IDEzLCBmaWcuaGVpZ2h0ID0gNX0KaGlzdF93Y19mdW4obWFya19PUlMsICJwY3QuMiIpCmBgYAoKIyMjIFNlbGVjdGlvbgoKVGhlIGJlc3QgbWFya2VycyBoYXZlIGhpZ2ggcGN0LjEgYW5kIGxvdyBwY3QuMiA6CgpgYGB7ciBtYXJrX09SU19zZWxlY3R9Cm1hcmtfT1JTID0gbWFya19PUlMgJT4lCiAgZHBseXI6OmZpbHRlcihwY3QuMSA+IDAuNiAmIHBjdC4yIDwgMC4zKQoKbGlzdF9yZXN1bHRzW1tncm91cF9uYW1lXV0kY2hvb3Nlbl9vbmVzID0gbWFya19PUlMKCm1hcmtfT1JTCmBgYAoKV2UgdmlzdWFsaXplIGV4cHJlc3Npb24gbGV2ZWxzIG9mIHRob3NlIGdlbmVzIG9uIHRoZSBwcm9qZWN0aW9uIDoKCmBgYHtyIG1hcmtfT1JTX3NlbGVjdF9zZWUsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gNn0KcGxvdF9saXN0ID0gbGFwcGx5KHJvd25hbWVzKG1hcmtfT1JTKSwgRlVOID0gZnVuY3Rpb24ob25lX2dlbmUpIHsKICBTZXVyYXQ6OkZlYXR1cmVQbG90KHNvYmosIGZlYXR1cmVzID0gb25lX2dlbmUsCiAgICAgICAgICAgICAgICAgICAgICByZWR1Y3Rpb24gPSBuYW1lMkQpICsKICAgIGdncGxvdDI6OnRoZW1lKGFzcGVjdC5yYXRpbyA9IDEpICsKICAgIGdncGxvdDI6OnNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBhcXVhcml1czo6Y29sb3JfZ2VuZSkgKwogICAgU2V1cmF0OjpOb0F4ZXMoKQp9KQoKcGF0Y2h3b3JrOjp3cmFwX3Bsb3RzKHBsb3RfbGlzdCwgbmNvbCA9IDMpCmBgYAoKIyMgSUZFYiBtYXJrZXJzCgpJbiB0aGlzIHNlY3Rpb24sIHdlIGNvbXBhcmVkIElGRWIgdG8gb3RoZXIgY2VsbHMuCgpgYGB7ciBzZWVfSUZFYiwgZmlnLndpZHRoID0gNiwgZmlnLmhlaWdodCA9IDR9Cmdyb3VwX25hbWUgPSAiSUZFYl92c19hbGwiCgphcXVhcml1czo6cGxvdF9yZWRfYW5kX2JsdWUoc29iaiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwMSA9ICJJRkUgYmFzYWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVkdWN0aW9uID0gbmFtZTJEKSArCiAgZ2dwbG90Mjo6bGFicyh0aXRsZSA9IGdyb3VwX25hbWUpCmBgYAoKIyMjIERpZmZlcmVudGlhbCBleHByZXNzaW9uCgpXZSBpZGVudGlmeSBzcGVjaWZpYyBtYXJrZXJzIGZvciBlYWNoIHBvcHVsYXRpb24gOgoKYGBge3IgZGVfSUZFYn0KbWFyayA9IFNldXJhdDo6RmluZE1hcmtlcnMoc29iaiwgaWRlbnQuMSA9ICJJRkUgYmFzYWwiKQoKbWFyayA9IG1hcmsgJT4lCiAgZHBseXI6OmZpbHRlcihwX3ZhbF9hZGogPCAwLjA1KSAlPiUKICBkcGx5cjo6YXJyYW5nZSgtYXZnX2xvZ0ZDLCBwY3QuMSAtIHBjdC4yKQptYXJrJGdlbmVfbmFtZSA9IHJvd25hbWVzKG1hcmspCgpsaXN0X3Jlc3VsdHNbW2dyb3VwX25hbWVdXSRtYXJrID0gbWFyawoKZGltKG1hcmspCmhlYWQobWFyaywgbiA9IDIwKQpgYGAKCkhvdyBtYW55IGdlbmVzIGVucmljaGVkIGluIElGRWIgPwoKYGBge3IgbWFya19JRkVifQptYXJrX0lGRWIgPSBtYXJrICU+JQogIGRwbHlyOjpmaWx0ZXIoYXZnX2xvZ0ZDID4gMCkKCm5yb3cobWFya19JRkViKQpgYGAKCldlIGN1dCBwY3QuMSBhbmQgcGN0LjIgYnkgYmlucyBvZiAwLjEgOgoKYGBge3IgbWFya19jdXRfSUZFYn0KbWFya19JRkViJHBjdC4xX2N1dCA9IGN1dChtYXJrX0lGRWIkcGN0LjEsIGJyZWFrcyA9IDEwKQptYXJrX0lGRWIkcGN0LjJfY3V0ID0gY3V0KG1hcmtfSUZFYiRwY3QuMiwgYnJlYWtzID0gMTApCgpoZWFkKG1hcmtfSUZFYikKYGBgCgoKIyMjIFZpc3VhbGl6YXRpb24KCldlIG1ha2UgYSBoaXN0b2dyYW0gZm9yIGBwY3QuMWAsIGBwY3QuMmAgYW5kIGBhdmdfbG9nRkNgLgoKYGBge3IgaGlzdF9mY19JRkViXzEsIGZpZy53aWR0aCA9IDEzLCBmaWcuaGVpZ2h0ID0gNX0KaGlzdF93Y19mdW4obWFya19JRkViLCAicGN0LjEiKQpgYGAKCmBgYHtyIGhpc3RfZmNfSUZFYl8yLCBmaWcud2lkdGggPSAxMywgZmlnLmhlaWdodCA9IDV9Cmhpc3Rfd2NfZnVuKG1hcmtfSUZFYiwgInBjdC4yIikKYGBgCgojIyMgU2VsZWN0aW9uCgpUaGUgYmVzdCBtYXJrZXJzIGhhdmUgaGlnaCBwY3QuMSBhbmQgbG93IHBjdC4yIDoKCmBgYHtyIG1hcmtfSUZFYl9zZWxlY3R9Cm1hcmtfSUZFYiA9IG1hcmtfSUZFYiAlPiUKICBkcGx5cjo6ZmlsdGVyKHBjdC4xID4gMC42ICYgcGN0LjIgPCAwLjIpCgpsaXN0X3Jlc3VsdHNbW2dyb3VwX25hbWVdXSRjaG9vc2VuX29uZXMgPSBtYXJrX0lGRWIKCm1hcmtfSUZFYgpgYGAKCldlIHZpc3VhbGl6ZSBleHByZXNzaW9uIGxldmVscyBvZiB0aG9zZSBnZW5lcyBvbiB0aGUgcHJvamVjdGlvbiA6CgpgYGB7ciBtYXJrX0lGRWJfc2VsZWN0X3NlZSwgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSAxMn0KcGxvdF9saXN0ID0gbGFwcGx5KHJvd25hbWVzKG1hcmtfSUZFYiksIEZVTiA9IGZ1bmN0aW9uKG9uZV9nZW5lKSB7CiAgU2V1cmF0OjpGZWF0dXJlUGxvdChzb2JqLCBmZWF0dXJlcyA9IG9uZV9nZW5lLAogICAgICAgICAgICAgICAgICAgICAgcmVkdWN0aW9uID0gbmFtZTJEKSArCiAgICBnZ3Bsb3QyOjp0aGVtZShhc3BlY3QucmF0aW8gPSAxKSArCiAgICBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gYXF1YXJpdXM6OmNvbG9yX2dlbmUpICsKICAgIFNldXJhdDo6Tm9BeGVzKCkKfSkKCnBhdGNod29yazo6d3JhcF9wbG90cyhwbG90X2xpc3QsIG5jb2wgPSAzKQpgYGAKCgojIFNhdmUKCldlIHNhdmUgdGhlIGxpc3Qgb2YgcmVzdWx0cyA6CgpgYGB7ciBzYXZlX2xpc3RfcmVzdWx0c30Kc2F2ZVJEUyhsaXN0X3Jlc3VsdHMsIGZpbGUgPSBwYXN0ZTAob3V0X2RpciwgIi9vcnNfaWZlYl9tYXJrZXJzLnJkcyIpKQpgYGAKCldlIGFsc28gc2F2ZSBhcyBYTFNYIGZpbGUgOgoKYGBge3Igc2F2ZV9saXN0X3Jlc3VsdHMyfQpsaXN0X3Jlc3VsdHMyID0gbGlzdChPUlNfdnNfYWxsID0gbGlzdF9yZXN1bHRzJE9SU192c19hbGwkbWFyaywKICAgICAgICAgICAgICAgICAgICAgT1JTX3ZzX2FsbF9zZWxlY3Rpb24gPSBsaXN0X3Jlc3VsdHMkT1JTX3ZzX2FsbCRjaG9vc2VuX29uZXMsCiAgICAgICAgICAgICAgICAgICAgIElGRWJfdnNfYWxsID0gbGlzdF9yZXN1bHRzJElGRWJfdnNfYWxsJG1hcmssCiAgICAgICAgICAgICAgICAgICAgIElGRWJfdnNfYWxsX3NlbGVjdGlvbiA9IGxpc3RfcmVzdWx0cyRJRkViX3ZzX2FsbCRjaG9vc2VuX29uZXMpCgpvcGVueGxzeDo6d3JpdGUueGxzeChsaXN0X3Jlc3VsdHMyLCBmaWxlID0gcGFzdGUwKG91dF9kaXIsICIvb3JzX3ZzX2lmZWJfbWFya2Vycy54bHN4IikpCmBgYAoKCiMgUiBTZXNzaW9uCgpgYGB7ciBzZXNzaW9uaW5mbywgZWNobyA9IEZBTFNFLCBmb2xkX291dHB1dCA9IFRSVUV9CnNlc3Npb25JbmZvKCkKYGBgCgo=